package com.kapcb.context.core;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.kapcb.context.bean.ThreadContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;

import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * <a>Title: DefaultThreadContextImpl </a>
 * <a>Author: kapcb <a>
 * <a>Description: DefaultThreadContextImpl <a>
 *
 * @author kapcb
 * @version 1.0
 * @date 2024/4/20 1:31 PM
 * @since 1.0
 */
@Slf4j
public class DefaultThreadContextImpl implements IThreadContext {

    /**
     * 本地线程上下文变量
     */
    private final ThreadLocal<ThreadContext> contextThreadLocal = new ThreadLocal<>();

    /**
     * 清除线程上下文内容
     *
     * @param threadContext 线程上下文对象
     */
    private void doClearContext(ThreadContext threadContext) {
        for (Object value : threadContext.values()) {
            // 需要调用 close 方法的对象
            if (value instanceof AutoCloseable) {
                log.warn("本地线程上下文中包含资源连接对象");
//                try {
//                    ((AutoCloseable) value).close();
//                } catch (Exception e) {
//                    throw new RuntimeException(e);
//                }
            }
        }

        // 清空线程上下文数据存储容器中数据
        threadContext.clear();
        // 清空本地线程上下文变量
        this.contextThreadLocal.remove();
    }

    /**
     * 私有的获取线程上下文
     */
    private ThreadContext get() {
        ThreadContext threadContext = contextThreadLocal.get();
        if (MapUtils.isEmpty(threadContext)) {
            threadContext = new ThreadContext();
            contextThreadLocal.set(threadContext);
        }
        return threadContext;
    }

    /**
     * 深拷贝
     *
     * @param value 值
     * @return 深拷贝后的值
     */
    private Object deepCopyItem(Object value) {
        if (Objects.isNull(value)) {
            return null;
        }
        // 如果实现了克隆方法
        if (value instanceof Cloneable && value instanceof Serializable) {
            return ObjectUtil.cloneByStream(value);
        }
        // 字符串直接返回
        if (value instanceof String) {
            return value;
        }
        // 数字类型直接返回
        if (value instanceof Number) {
            return value;
        }
        // 布尔类型类型直接返回
        if (value instanceof Boolean) {
            return value;
        }
        //使用 JSON 反序列化

        String jsonString = JSONUtil.toJsonStr(value);
        return JSONUtil.toBean(jsonString, value.getClass());
    }

    /**
     * 初始化线程上下文
     */
    @Override
    public void init() {
        // 本地线程上下文变量中是否已经存在数据对象
        ThreadContext threadContext = contextThreadLocal.get();
        if (MapUtils.isNotEmpty(threadContext)) {
            // 存在数据对象则先清除本地上下文中的变量
            doClearContext(threadContext);
        }

        // 初始化新的线程上下文数据存储容器
        contextThreadLocal.set(new ThreadContext());
    }

    /**
     * 存放数据到线程上下文
     *
     * @param key   键
     * @param value 值
     * @return 值
     */
    @Override
    public <T> T put(String key, T value) {
        return (T) this.get().put(key, value);
    }

    /**
     * 根据 key 获取线程上下文中的数据
     *
     * @param key 键
     * @return 值
     */
    @Override
    public <T> T get(String key) {
        return (T) this.get().get(key);
    }

    /**
     * 根据 key 移除线程上下文中的数据
     *
     * @param key 键
     * @return 值
     */
    @Override
    public <T> T remove(String key) {
        return (T) this.get().remove(key);
    }

    /**
     * 清除线程上下文
     */
    @Override
    public void clearContext() {
        ThreadContext threadContext = contextThreadLocal.get();
        if (MapUtils.isEmpty(threadContext)) {
            threadContext = new ThreadContext();
        }
        doClearContext(threadContext);
    }

    /**
     * 浅拷贝线程上下文数据
     *
     * @return 线程上下文容器
     */
    @Override
    public ThreadContext copyContext() {
        ThreadContext threadContext = get();
        // 浅拷贝
        return (ThreadContext) threadContext.clone();
    }

    /**
     * 复制线程上下文内容
     * 深拷贝
     *
     * @return 线程上下文容器
     */
    @Override
    public ThreadContext deepCopyContext() {
        ThreadContext threadContext = contextThreadLocal.get();
        ThreadContext copyThreadContext = new ThreadContext();
        if (MapUtils.isEmpty(threadContext)) {
            return copyThreadContext;
        }

        // 逐一进行深拷贝
        threadContext.entrySet().iterator().forEachRemaining(e -> copyThreadContext.put(e.getKey(), deepCopyItem(e.getValue())));
        return copyThreadContext;
    }

    /**
     * 获取线程上下文的所有 k
     *
     * @return 线程上下文的所有 k
     */
    @Override
    public Set<String> keySet() {
        return get().keySet();
    }

    /**
     * 获取线程上下文的所有 k-v 集合
     *
     * @return 线程上下文的所有 k-v 集合
     */
    @Override
    public Set<Map.Entry<String, Object>> entrySet() {
        return get().entrySet();
    }

}
